    // https://juejin.cn/post/6844903929705136141#heading-2
    // 常用变量类型
    const mapTag = '[object Map]';
    const setTag = '[object Set]';
    const arrayTag = '[object Array]';
    const objectTag = '[object Object]';

    const boolTag = '[object Boolean]';
    const dateTag = '[object Date]';
    const errorTag = '[object Error]';
    const numberTag = '[object Number]';
    const regexpTag = '[object RegExp]';
    const stringTag = '[object String]';
    const symbolTag = '[object Symbol]';

    const deepTag = [mapTag, setTag, arrayTag, objectTag, boolTag, dateTag, errorTag, numberTag, regexpTag, stringTag,
        symbolTag
    ]

    // 深拷贝
    function clone(target, map = new WeakMap()) {
        // 克隆原始类型
        if (!isObject(target)) {
            return target;
        }

        // 初始化
        const type = getType(target);
        let cloneTarget;
        // 复制类型 如果是个对象 {}  那么就生成一个对象的原型链
        if (deepTag.includes(type)) {
            cloneTarget = getInit(target, type);
        }

        // 如果已经缓存过 直接返回缓存
        // 防止循环引用
        if (map.get(target)) {
            return map.get(target);
        }
        map.set(target, cloneTarget);

        // 克隆set
        if (type === setTag) {
            target.forEach(value => {
                // set只能通过add添加
                cloneTarget.add(clone(value, map));
            });
            return cloneTarget;
        }

        // 克隆map
        if (type === mapTag) {
            target.forEach((value, key) => {
                // map只能通过set添加
                cloneTarget.set(key, clone(value, map));
            });
            return cloneTarget;
        }

        // 克隆对象和数组
        const keys = type === arrayTag ? undefined : Object.keys(target);
        forEach(keys || target, (value, key) => {
            if (keys) {
                key = value;
            }
            cloneTarget[key] = clone(target[key], map);
        })

        return cloneTarget;
    };

    // 获取对象的原型
    function getInit(target) {
        const Ctor = target.constructor;
        return new Ctor();
    }

    // while循环是最快的 
    function forEach(array, iteratee) {
        let index = -1;
        const length = array.length;
        while (++index < length) {
            iteratee(array[index], index);
        }
        return array;
    }

    // 获取变量的实际类型
    function getType(target) {
        return Object.prototype.toString.call(target);
    }

    // 判断对象是否为引用类型
    function isObject(target) {
        const type = typeof target;
        return target !== null && (type === 'object' || type === 'function');
    }

    const target = {
        field1: 1,
        field2: undefined,
        field3: {
            child: 'child'
        },
        field4: [2, 4, 8]
    };
    // 对象存在循环引用的情况，即对象的属性间接或直接的引用了自身的情况
    target.target = target;
    const Setv = new Set()
    Setv.add('name', '张三')
    target.setMap = Setv;

    // console.log('clone ===> ', clone(a), a === clone(a))
    console.log('clone ===> ', clone(target))